﻿using ChartManager.Controllers;
using ChartManager.CustomControls;
using ChartManager.Migrations;
using ChartManager.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ChartManager
{
    public partial class Form1 : Form
    {
        private EFContext context;

        public Form1()
        {
            InitializeComponent();
            context = new EFContext();
            // 程序自动迁移数据库，会多次调用Seed，因而Controller会抛出异常，因此用try-catch防止多次增加，暂时没有更好的方法
            // 此行似乎会连接数据库，这样在之后操作中就不会卡顿了
            try
            {
                new DbMigrator(new Configuration()).Update();
            }
            catch { }
            //test
            /*
            SongController.AddSongs(context, new Song() { Singers = new List<string> { "at17" }, Name = "18" });
            /**/
            // 点击一下显示标题
            QueryChartMenuItem.PerformClick();
        }

        /// <summary>
        /// 设置4个主panel的可见性
        /// </summary>
        /// <param name="visible">默认为false</param>
        private void SetPanelVisible(bool visible = false)
        {
            Panel[] panels = new Panel[]
            {
                pQueryChart,
                pAddChart,
                pAddSong,
                pQuerySong,
            };
            foreach (var panel in panels) panel.Visible = visible;
        }

        private void QueryChartMenuItem_Click(object sender, EventArgs e)
        {
            SetPanelVisible();
            pQueryChart.Visible = true;
            // Tag存储了当前查询面板结果的标题，若Tag为空，则表示没有查询过，显示一般标题，否则显示Tag标题
            Text = Tag?.ToString() ?? $"{Constants.ChartName} - {(sender as ToolStripMenuItem).Text}";
            dateTimePicker1.Focus();
        }

        private void AddChartToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SetPanelVisible();
            pAddChart.Visible = true;
            Text = $"{Constants.ChartName} - {(sender as ToolStripMenuItem).Text}";
            dateTimePicker2.Focus();
        }

        private void AddSongToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SetPanelVisible();
            pAddSong.Visible = true;
            Text = $"{Constants.ChartName} - {(sender as ToolStripMenuItem).Text}";
            txbSingers.Focus();
        }

        private void QuerySongToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SetPanelVisible();
            pQuerySong.Visible = true;
            Text = $"{Constants.ChartName} - {(sender as ToolStripMenuItem).Text}";
            InitialQuerySongTable(pQuerySong);
        }

        /// <summary>
        /// 查询榜单的日期选择
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
        {
            var queryDate = ChartController.GetCharts(context).Select(chart => chart.ReleaseTime.Date);
            var picker = sender as DateTimePicker;
            var panel = picker.Parent as TableLayoutPanel;
            // 如果选择的日期在数据库中存在榜单，则显示榜单
            if (queryDate.Contains(picker.Value.Date))
                ShowChart(panel, picker.Value);
            // 否则清空榜单和Tag
            else
            {
                while (panel.Controls.Count > 1)
                    panel.Controls.RemoveAt(1);
                Tag = Text = $"{Constants.ChartName} - {QueryChartMenuItem.Text}";
            }
        }

        /// <summary>
        /// 显示榜单
        /// </summary>
        /// <param name="panel">父面板</param>
        /// <param name="time">日期</param>
        private void ShowChart(TableLayoutPanel panel, DateTime time)
        {
            var chart = ChartController.GetSingleChart(context, time);

            // 清空面板
            while (panel.Controls.Count > 1)
                panel.Controls.RemoveAt(1);
            // 构造表
            var table = new TableLayoutPanel() { ColumnCount = 6, RowCount = Constants.SongsCount + 1 };
            // 列样式
            table.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 1F));
            table.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 2F));
            table.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 1F));
            table.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 1F));
            table.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 1F));
            table.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 1F));
            // 表头
            table.Controls.Add(new HeaderLabel("Rank"), 0, 0);
            table.Controls.Add(new HeaderLabel("歌曲"), 1, 0);
            table.Controls.Add(new HeaderLabel("LW"), 2, 0);
            table.Controls.Add(new HeaderLabel("WO"), 3, 0);
            table.Controls.Add(new HeaderLabel("Peak"), 4, 0);
            table.Controls.Add(new HeaderLabel("变动"), 5, 0);

            // 填写数据
            foreach (var row in chart.Rows)
            {
                table.Controls.Add(new ReadOnlyTextBox(row.Rank.ToString()), 0, row.Rank);
                table.Controls.Add(new ReadOnlyTextBox($"{row.Song.SingersAsString} - {row.Song.Name}"), 1, row.Rank);
                table.Controls.Add(new ReadOnlyTextBox(row.LastWeek.HasValue ? row.LastWeek.Value.ToString() : "--"), 2, row.Rank);
                table.Controls.Add(new ReadOnlyTextBox(row.WeekOn.ToString()), 3, row.Rank);
                table.Controls.Add(new ReadOnlyTextBox(row.Peak.ToString()), 4, row.Rank);
                // 若本次循环中有LastWeek，即非新上榜，则计算变动，若变动为0，则为→←，否则根据正负填写
                if (row.LastWeek.HasValue)
                {
                    var difference = row.LastWeek.Value - row.Rank;
                    var szDifference = "→←";
                    if (difference != 0)
                        szDifference = string.Format("{0}{1}", difference < 0 ? "↓" : "↑", Math.Abs(difference));
                    table.Controls.Add(new ReadOnlyTextBox(szDifference), 5, row.Rank);
                }
                // 新上榜填↑↑
                else
                    table.Controls.Add(new ReadOnlyTextBox("↑↑"), 5, row.Rank);
            }

            // 尝试获取出榜歌曲，若为最早的榜单可能会抛出异常
            try
            {
                var outSongs = ChartController.GetOutSongs(context, chart);
                // 若存在出榜歌曲，则填入次表头和数据
                if (outSongs.Count() > 0)
                {
                    table.RowCount += outSongs.Count() + 1;
                    table.Controls.Add(new HeaderLabel("出榜歌曲"), 1, Constants.SongsCount + 1);

                    for (int i = 0; i < outSongs.Count(); i++)
                    {
                        table.Controls.Add(new OutSongTextBox($"{outSongs.ElementAt(i).Song.SingersAsString} - {outSongs.ElementAt(i).Song.Name}"), 1, Constants.SongsCount + 2 + i);
                        table.Controls.Add(new OutSongTextBox(outSongs.ElementAt(i).Rank.ToString()), 2, Constants.SongsCount + 2 + i);
                        table.Controls.Add(new OutSongTextBox(outSongs.ElementAt(i).WeekOn.ToString()), 3, Constants.SongsCount + 2 + i);
                        table.Controls.Add(new OutSongTextBox(outSongs.ElementAt(i).Peak.ToString()), 4, Constants.SongsCount + 2 + i);
                    }
                }
            }
            catch (IndexOutOfRangeException)
            {

            }
            
            // 表格的其他样式
            table.CellBorderStyle = TableLayoutPanelCellBorderStyle.Inset;
            table.AutoSize = true;
            // 表格构造完毕，加入到主面板中，并修改标题和Tag
            panel.Controls.Add(table, 0, 1);
            Tag = Text = $"{Constants.ChartName} ({chart.ReleaseTime:yyyy-MM-dd}期)";
        }

        /// <summary>
        /// 新增榜单的日期选择
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dateTimePicker2_ValueChanged(object sender, EventArgs e)
        {
            var picker = sender as DateTimePicker;
            var panel = picker.Parent as TableLayoutPanel;
            // 清空父面板
            while (panel.Controls.Count > 1)
                panel.Controls.RemoveAt(1);
            // 若选择的日期非发布日期，返回
            if (picker.Value.DayOfWeek != Constants.ReleaseDay)
                return;
            // 若选择的日期已经存在榜单，返回
            if (ChartController.GetSingleChart(context, picker.Value) != null)
                return;

            // 构造表
            var table = new TableLayoutPanel() { ColumnCount = 4, RowCount = Constants.SongsCount + 2 };
            // 表样式
            table.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 3F));
            table.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 18F));
            table.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 4F));
            table.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 4F));
            // 表头
            table.Controls.Add(new HeaderLabel("Rank"), 0, 0);
            table.Controls.Add(new HeaderLabel("歌曲"), 1, 0);
            table.Controls.Add(new HeaderLabel("从上周歌曲"), 2, 0);
            table.Controls.Add(new HeaderLabel("从新增歌曲"), 3, 0);

            // 存储输入框
            var textBoxs = new List<SongTextBox>();

            // 构造表内容控件
            for (int i = 1; i < Constants.SongsCount + 1; i++)
            {
                table.Controls.Add(new HeaderLabel(i.ToString()), 0, i);
                var textBox = new SongTextBox();
                table.Controls.Add(textBox, 1, i);
                textBoxs.Add(textBox);
                table.Controls.Add(new SelectButton("选择", textBox, context, SelectMode.LastWeek), 2, i);
                table.Controls.Add(new SelectButton("选择", textBox, context, SelectMode.New), 3, i);
            }

            // 表尾控件
            var btnConfirm = new TextButton("确定");
            var btnCancel = new TextButton("清空");

            btnConfirm.Click += (object btn, EventArgs ebtn) =>
            {
                // 将输入框按所在行序排序
                textBoxs = textBoxs.OrderBy(box => table.GetRow(box)).ToList();
                var songs = new Song[Constants.SongsCount];
                // 添加榜单
                try
                {
                    for (int i = 0; i < Constants.SongsCount; i++)
                    {
                        // 检查输入框是否存有歌曲，若没有，则按照输入框的内容，转化为假歌曲信息，根据此歌曲信息获取歌曲实体，放入歌曲集合中
                        var fakeSong = textBoxs[i].Text.toSong();
                        // 如果是手输的输入框，输入框必然没有song，从榜单中查询，如果榜单中也没有，才以fakeSong增加新的歌曲
                        textBoxs[i].song = songs[i] = (textBoxs[i].song ?? SongController.GetSingleSong(context, fakeSong.Singers, fakeSong.Name)) ?? fakeSong;
                    }
                    ChartController.AddChart(context, picker.Value.Year, picker.Value.Month, picker.Value.Day, songs);
                    MessageBox.Show("添加成功");
                    btnCancel.PerformClick();
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"添加失败，原因: {ex.Message}");
                }
            };
            table.Controls.Add(btnConfirm, 0, Constants.SongsCount + 1);

            btnCancel.Click += (object btn, EventArgs ebtn) =>
            {
                // 清空各输入框的歌曲信息，重新激活输入框
                foreach (var textbox in textBoxs)
                {
                    textbox.song = null;
                    textbox.ReadOnly = false;
                }
            };
            table.Controls.Add(btnCancel, 0, Constants.SongsCount + 1);

            // 表格的其他样式
            table.CellBorderStyle = TableLayoutPanelCellBorderStyle.Inset;
            table.AutoSize = true;
            // 增加到父面板中
            panel.Controls.Add(table, 0, 1);
        }

        /// <summary>
        /// 添加歌曲的清空按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnCancel_Click(object sender, EventArgs e)
        {
            txbSingers.Text = string.Empty;
            txbName.Text = string.Empty;
            txbSingers.Focus();
        }

        /// <summary>
        /// 添加歌曲的确定按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnConfirm_Click(object sender, EventArgs e)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(txbSingers.Text))
                    throw new Exception("歌手输入框为空");
                if (string.IsNullOrWhiteSpace(txbName.Text))
                    throw new Exception("歌名输入框为空");
                // 根据两个输入框构造新歌曲
                var newSong = new Song() { SingersAsString = txbSingers.Text, Name = txbName.Text };
                // 添加新歌曲
                SongController.AddSongs(context, new Song[] { newSong });
                MessageBox.Show("添加成功");
                // 添加成功后清空输入内容
                btnCancel.PerformClick();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"添加失败，原因: {ex.Message}");
            }
        }

        /// <summary>
        /// 初始化查询歌曲表
        /// </summary>
        /// <param name="panel"></param>
        private void InitialQuerySongTable(TableLayoutPanel panel)
        {
            // 若父面板已经有控件了，则说明已经被初始化了，此时返回不操作
            if (panel.Controls.Count != 0)
                return;
            // 面板样式
            panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 1F));
            panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 1F));
            panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 1F));
            panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 1F));
            panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 1F));
            // 面板子控件
            var textBox = new SongTextBox();
            var btnLastWeek = new SelectButton("从上周选择", textBox, context, SelectMode.LastWeek);
            var btnAll = new SelectButton("从所有选择", textBox, context, SelectMode.All);
            var btnQuery = new TextButton("确定");
            var btnCancel = new TextButton("清空");
            // 选择按钮点击后立即查询
            btnLastWeek.Click += (s, e) => btnQuery.PerformClick();
            btnAll.Click += (s, e) => btnQuery.PerformClick();
            // 添加控件
            panel.Controls.Add(textBox, 0, 0);
            panel.Controls.Add(btnLastWeek, 1, 0);
            panel.Controls.Add(btnAll, 2, 0);

            btnQuery.Click += (object sender, EventArgs e) =>
            {
                Song song = null;
                try
                {
                    // 获取输入框的歌曲信息，或按输入框文本转换的歌曲
                    song = textBox.song ?? textBox.Text.toSong();
                }
                catch (ArgumentException) { }
                // 没有歌曲或输入格式错误时返回
                if (song == null) return;
                // 已获得歌曲，清空面板
                while (panel.Controls.Count > 5)
                    panel.Controls.RemoveAt(5);
                // 获取歌曲信息
                var info = SongController.GetSongInfo(context, song);
                if (!info.WasOnChart) return;

                // 根据获取的歌曲信息，按WeekOn倒序排序，则可以得到最终WeekOn
                var WeekOn = (from row in info.Records
                              orderby row.WeekOn descending
                              select row.WeekOn).First();
                // 根据获取的歌曲信息，按Peak顺序排序，则可以得到最终Peak
                var Peak = (from row in info.Records
                            orderby row.Peak
                            select row.Peak).First();
                // 将最终结果写入第二行第一格中
                panel.Controls.Add(new ReadOnlyTextBox($"WeekOn: {WeekOn} Peak: {Peak}"), 0, 1);

                // 构造详细表格
                var table = new TableLayoutPanel() { ColumnCount = 6, RowCount = info.Records.Count + 1 };
                // 表头
                table.Controls.Add(new HeaderLabel("历史"), 0, 0);
                table.Controls.Add(new HeaderLabel("Rank"), 1, 0);
                table.Controls.Add(new HeaderLabel("LW"), 2, 0);
                table.Controls.Add(new HeaderLabel("WO"), 3, 0);
                table.Controls.Add(new HeaderLabel("Peak"), 4, 0);
                table.Controls.Add(new HeaderLabel("变动"), 5, 0);

                // 如查询榜单，逐一填入每行记录信息
                foreach (var row in info.Records)
                {
                    table.Controls.Add(new HeaderLabel($"{Constants.ChartName} ({row.Chart.ReleaseTime:yyyy-MM-dd}期)"));
                    table.Controls.Add(new HeaderLabel(row.Rank.ToString()));
                    table.Controls.Add(new HeaderLabel(row.LastWeek.HasValue ? row.LastWeek.Value.ToString() : "--"));
                    table.Controls.Add(new HeaderLabel(row.WeekOn.ToString()));
                    table.Controls.Add(new HeaderLabel(row.Peak.ToString()));
                    if (row.LastWeek.HasValue)
                    {
                        var difference = row.LastWeek.Value - row.Rank;
                        var szDifference = "→←";
                        if (difference != 0)
                            szDifference = string.Format("{0}{1}", difference < 0 ? "↓" : "↑", Math.Abs(difference));
                        table.Controls.Add(new HeaderLabel(szDifference));
                    }
                    else
                        table.Controls.Add(new HeaderLabel("↑↑"));
                }

                // 其他样式
                table.CellBorderStyle = TableLayoutPanelCellBorderStyle.Inset;
                table.AutoSize = true;
                table.Dock = DockStyle.Fill;
                // 增加到第三行第一格
                panel.Controls.Add(table, 0, 2);
            };
            // 查询按钮增加
            panel.Controls.Add(btnQuery, 3, 0);

            btnCancel.Click += (s, e) =>
            {
                // 清空输入框的歌曲，并重新激活输入框
                textBox.song = null;
                textBox.ReadOnly = false;
                // 清空下方内容
                while (panel.Controls.Count > 5)
                    panel.Controls.RemoveAt(5);
            };
            // 清空按钮增加
            panel.Controls.Add(btnCancel, 4, 0);
        }
    }
}
